require 'pathname'
require 'tmpdir'
require 'digest/md5'
require 'fileutils'

Puppet::Type.type(:downloaded_package).provide(:wget) do
  defaultfor kernel: :Linux

  confine :true => begin
    [:wget, :tar, :rm, :unzip].inject(true) do |result, cmd|
      result && Puppet::Util.which(cmd.to_s)
    end
  end

  commands :wget => 'wget', :tar => 'tar', :rm => 'rm', :unzip => 'unzip'

  def exists?
    Pathname.new(destdir).directory?
  end

  def create
    FileUtils.rm_r(tempdir) if Dir.exist?(tempdir)
    Dir.mkdir(tempdir)
    Dir.chdir(tempdir) do
      wget(resource[:source])
      extract_method(filetype).call(packagename)
      FileUtils.chown_R(resource[:owner], nil, destdir)
    end
  end

  def destroy
    rm('-fr', destdir)
  end

  def tempdir
    @tempdir ||= File.join(Dir.tmpdir, 'downloaded_package-' + Digest::MD5.hexdigest(resource[:source]))
  end

  def packagename
    @package_name ||= resource[:source].gsub(/https?:.*\/([a-zA-Z0-9\-\._]+(\.tar\.gz|\.tar\.xz|\.zip))$/, '\1')
  end

  def destdir
    @destdir ||= resource[:install_dir] + '/' + packagename.sub(/(\.tar\.gz|\.tar\.xz|\.zip)$/, '')
  end

  #fetch postfix of compressed file, like '.tar.gz', '.zip' etc.
  def filetype
    @compressed_file_type ||= /.*(\.tar\.gz|\.tar\.xz|\.zip)$/.match(packagename)[1]
  end

  def extract_method(postfix)
    @extract_map ||= {
      '.tar.gz' => proc { |filename|
        tar('-C', resource[:install_dir], '-xzvf', filename)
      },
      '.tar.xz' => proc { |filename|
        tar('-C', resource[:install_dir], '-xJvf', filename)
      },
      '.zip' => proc { |filename|
        unzip(filename, '-d', resource[:install_dir])
      }
    }
    @extract_map[postfix]
  end
end
